home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / ex_vops2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  18.5 KB  |  910 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)ex_vops2.c    6.9 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  9. #endif not lint
  10.  
  11. #include "ex.h"
  12. #include "ex_tty.h"
  13. #include "ex_vis.h"
  14.  
  15. /*
  16.  * Low level routines for operations sequences,
  17.  * and mostly, insert mode (and a subroutine
  18.  * to read an input line, including in the echo area.)
  19.  */
  20. extern char    *vUA1, *vUA2;        /* mjm: extern; also in ex_vops.c */
  21. extern char    *vUD1, *vUD2;        /* mjm: extern; also in ex_vops.c */
  22.  
  23. /*
  24.  * Obleeperate characters in hardcopy
  25.  * open with \'s.
  26.  */
  27. bleep(i, cp)
  28.     register int i;
  29.     char *cp;
  30. {
  31.  
  32.     i -= column(cp);
  33.     do
  34.         ex_putchar('\\' | QUOTE);
  35.     while (--i >= 0);
  36.     rubble = 1;
  37. }
  38.  
  39. /*
  40.  * Common code for middle part of delete
  41.  * and change operating on parts of lines.
  42.  */
  43. vdcMID()
  44. {
  45.     register char *cp;
  46.  
  47.     squish();
  48.     setLAST();
  49.     if (FIXUNDO)
  50.         vundkind = VCHNG, CP(vutmp, linebuf);
  51.     if (wcursor < cursor)
  52.         cp = wcursor, wcursor = cursor, cursor = cp;
  53.     vUD1 = vUA1 = vUA2 = cursor; vUD2 = wcursor;
  54.     return (column(wcursor - 1));
  55. }
  56.  
  57. /*
  58.  * Take text from linebuf and stick it
  59.  * in the VBSIZE buffer BUF.  Used to save
  60.  * deleted text of part of line.
  61.  */
  62. takeout(BUF)
  63.     char *BUF;
  64. {
  65.     register char *cp;
  66.  
  67.     if (wcursor < linebuf)
  68.         wcursor = linebuf;
  69.     if (cursor == wcursor) {
  70.         beep();
  71.         return;
  72.     }
  73.     if (wcursor < cursor) {
  74.         cp = wcursor;
  75.         wcursor = cursor;
  76.         cursor = cp;
  77.     }
  78.     ex_setBUF(BUF);
  79.     if ((BUF[0] & (QUOTE|TRIM)) == OVERBUF)
  80.         beep();
  81. }
  82.  
  83. /*
  84.  * Are we at the end of the printed representation of the
  85.  * line?  Used internally in hardcopy open.
  86.  */
  87. ateopr()
  88. {
  89.     register int i, c;
  90.     register char *cp = vtube[destline] + destcol;
  91.  
  92.     for (i = WCOLS - destcol; i > 0; i--) {
  93.         c = *cp++;
  94.         if (c == 0)
  95.             return (1);
  96.         if (c != ' ' && (c & QUOTE) == 0)
  97.             return (0);
  98.     }
  99.     return (1);
  100. }
  101.  
  102. /*
  103.  * Append.
  104.  *
  105.  * This routine handles the top level append, doing work
  106.  * as each new line comes in, and arranging repeatability.
  107.  * It also handles append with repeat counts, and calculation
  108.  * of autoindents for new lines.
  109.  */
  110. bool    vaifirst;
  111. bool    gobbled;
  112. char    *ogcursor;
  113.  
  114. vappend(ch, cnt, indent)
  115.     int ch;        /* mjm: char --> int */
  116.     int cnt, indent;
  117. {
  118.     register int i;
  119.     register char *gcursor;
  120.     bool escape;
  121.     int repcnt, savedoomed;
  122.     short oldhold = hold;
  123. #ifdef    SIGWINCH
  124.     int oldmask;
  125. #endif
  126.  
  127.     /*
  128.      * Before a move in hardopen when the line is dirty
  129.      * or we are in the middle of the printed representation,
  130.      * we retype the line to the left of the cursor so the
  131.      * insert looks clean.
  132.      */
  133.     if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) {
  134.         rubble = 1;
  135.         gcursor = cursor;
  136.         i = *gcursor;
  137.         *gcursor = ' ';
  138.         wcursor = gcursor;
  139.         vmove();
  140.         *gcursor = i;
  141.     }
  142.     vaifirst = indent == 0;
  143.  
  144.     /*
  145.      * Handle replace character by (eventually)
  146.      * limiting the number of input characters allowed
  147.      * in the vgetline routine.
  148.      */
  149.     if (ch == 'r')
  150.         repcnt = 2;
  151.     else
  152.         repcnt = 0;
  153.  
  154.     /*
  155.      * If an autoindent is specified, then
  156.      * generate a mixture of blanks to tabs to implement
  157.      * it and place the cursor after the indent.
  158.      * Text read by the vgetline routine will be placed in genbuf,
  159.      * so the indent is generated there.
  160.      */
  161.     if (value(AUTOINDENT) && indent != 0) {
  162.         gcursor = genindent(indent);
  163.         *gcursor = 0;
  164.         vgotoCL(qcolumn(cursor - 1, genbuf));
  165.     } else {
  166.         gcursor = genbuf;
  167.         *gcursor = 0;
  168.         if (ch == 'o')
  169.             vfixcurs();
  170.     }
  171.  
  172.     /*
  173.      * Prepare for undo.  Pointers delimit inserted portion of line.
  174.      */
  175.     vUA1 = vUA2 = cursor;
  176.  
  177.     /*
  178.      * If we are not in a repeated command and a ^@ comes in
  179.      * then this means the previous inserted text.
  180.      * If there is none or it was too long to be saved,
  181.      * then beep() and also arrange to undo any damage done
  182.      * so far (e.g. if we are a change.)
  183.      */
  184.     if ((vglobp && *vglobp == 0) || peekbr()) {
  185.         if ((INS[0] & (QUOTE|TRIM)) == OVERBUF) {
  186.             beep();
  187.             if (!splitw)
  188.                 ungetkey('u');
  189.             doomed = 0;
  190.             hold = oldhold;
  191.             return;
  192.         }
  193.         /*
  194.          * Unread input from INS.
  195.          * An escape will be generated at end of string.
  196.          * Hold off n^^2 type update on dumb terminals.
  197.          */
  198.         vglobp = INS;
  199.         hold |= HOLDQIK;
  200.     } else if (vglobp == 0)
  201.         /*
  202.          * Not a repeated command, get
  203.          * a new inserted text for repeat.
  204.          */
  205.         INS[0] = 0;
  206.  
  207.     /*
  208.      * For wrapmargin to hack away second space after a '.'
  209.      * when the first space caused a line break we keep
  210.      * track that this happened in gobblebl, which says
  211.      * to gobble up a blank silently.
  212.      */
  213.     gobblebl = 0;
  214.  
  215. #ifdef    SIGWINCH
  216.     oldmask = sigblock(sigmask(SIGWINCH));
  217. #endif
  218.     /*
  219.      * Text gathering loop.
  220.      * New text goes into genbuf starting at gcursor.
  221.      * cursor preserves place in linebuf where text will eventually go.
  222.      */
  223.     if (*cursor == 0 || state == CRTOPEN)
  224.         hold |= HOLDROL;
  225.     for (;;) {
  226.         if (ch == 'r' && repcnt == 0)
  227.             escape = 0;
  228.         else {
  229.             gcursor = vgetline(repcnt, gcursor, &escape, ch);
  230.  
  231.             /*
  232.              * After an append, stick information
  233.              * about the ^D's and ^^D's and 0^D's in
  234.              * the repeated text buffer so repeated
  235.              * inserts of stuff indented with ^D as backtab's
  236.              * can work.
  237.              */
  238.             if (HADUP)
  239.                 addtext("^");
  240.             else if (HADZERO)
  241.                 addtext("0");
  242.             while (CDCNT > 0)
  243.                 addtext("\204"), CDCNT--;
  244.             if (gobbled)
  245.                 addtext(" ");
  246.             addtext(ogcursor);
  247.         }
  248.         repcnt = 0;
  249.  
  250.         /*
  251.          * Smash the generated and preexisting indents together
  252.          * and generate one cleanly made out of tabs and spaces
  253.          * if we are using autoindent.
  254.          */
  255.         if (!vaifirst && value(AUTOINDENT)) {
  256.             i = fixindent(indent);
  257.             if (!HADUP)
  258.                 indent = i;
  259.             gcursor = strend(genbuf);
  260.         }
  261.  
  262.         /*
  263.          * Limit the repetition count based on maximum
  264.          * possible line length; do output implied
  265.          * by further count (> 1) and cons up the new line
  266.          * in linebuf.
  267.          */
  268.         cnt = vmaxrep(ch, cnt);
  269.         CP(gcursor + 1, cursor);
  270.         do {
  271.             CP(cursor, genbuf);
  272.             if (cnt > 1) {
  273.                 int oldhold = hold;
  274.  
  275.                 Outchar = vinschar;
  276.                 hold |= HOLDQIK;
  277.                 ex_printf("%s", genbuf);
  278.                 hold = oldhold;
  279.                 Outchar = vputchar;
  280.             }
  281.             cursor += gcursor - genbuf;
  282.         } while (--cnt > 0);
  283.         endim();
  284.         vUA2 = cursor;
  285.         if (escape != '\n')
  286.             CP(cursor, gcursor + 1);
  287.  
  288.         /*
  289.          * If doomed characters remain, clobber them,
  290.          * and reopen the line to get the display exact.
  291.          */
  292.         if (state != HARDOPEN) {
  293.             DEPTH(vcline) = 0;
  294.             savedoomed = doomed;
  295.             if (doomed > 0) {
  296.                 register int cind = cindent();
  297.  
  298.                 physdc(cind, cind + doomed);
  299.                 doomed = 0;
  300.             }
  301.             i = vreopen(LINE(vcline), lineDOT(), vcline);
  302. #ifdef TRACE
  303.             if (trace)
  304.                 fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed);
  305. #endif
  306.             if (ch == 'R')
  307.                 doomed = savedoomed;
  308.         }
  309.  
  310.         /*
  311.          * All done unless we are continuing on to another line.
  312.          */
  313.         if (escape != '\n')
  314.             break;
  315.  
  316.         /*
  317.          * Set up for the new line.
  318.          * First save the current line, then construct a new
  319.          * first image for the continuation line consisting
  320.          * of any new autoindent plus the pushed ahead text.
  321.          */
  322.         killU();
  323.         addtext(gobblebl ? " " : "\n");
  324.         vsave();
  325.         cnt = 1;
  326.         if (value(AUTOINDENT)) {
  327. #ifdef LISPCODE
  328.             if (value(LISP))
  329.                 indent = lindent(dot + 1);
  330.             else
  331. #endif
  332.                  if (!HADUP && vaifirst)
  333.                 indent = whitecnt(linebuf);
  334.             vaifirst = 0;
  335.             strcLIN(vpastwh(gcursor + 1));
  336.             gcursor = genindent(indent);
  337.             *gcursor = 0;
  338.             if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2])
  339.                 gcursor = genbuf;
  340.             CP(gcursor, linebuf);
  341.         } else {
  342.             CP(genbuf, gcursor + 1);
  343.             gcursor = genbuf;
  344.         }
  345.  
  346.         /*
  347.          * If we started out as a single line operation and are now
  348.          * turning into a multi-line change, then we had better yank
  349.          * out dot before it changes so that undo will work
  350.          * correctly later.
  351.          */
  352.         if (FIXUNDO && vundkind == VCHNG) {
  353.             vremote(1, yank, 0);
  354.             undap1--;
  355.         }
  356.  
  357.         /*
  358.          * Now do the append of the new line in the buffer,
  359.          * and update the display.  If slowopen
  360.          * we don't do very much.
  361.          */
  362.         vdoappend(genbuf);
  363.         vundkind = VMANYINS;
  364.         vcline++;
  365.         if (state != VISUAL)
  366.             vshow(dot, NOLINE);
  367.         else {
  368.             i += LINE(vcline - 1);
  369.             vopen(dot, i);
  370.             if (value(SLOWOPEN))
  371.                 vscrap();
  372.             else
  373.                 vsync1(LINE(vcline));
  374.         }
  375.         strcLIN(gcursor);
  376.         *gcursor = 0;
  377.         cursor = linebuf;
  378.         vgotoCL(qcolumn(cursor - 1, genbuf));
  379.     }
  380.  
  381.     /*
  382.      * All done with insertion, position the cursor
  383.      * and sync the screen.
  384.      */
  385.     hold = oldhold;
  386.     if (cursor > linebuf)
  387.         cursor--;
  388.     if (state != HARDOPEN)
  389.         vsyncCL();
  390.     else if (cursor > linebuf)
  391.         back1();
  392.     doomed = 0;
  393.     wcursor = cursor;
  394.     vmove();
  395. #ifdef    SIGWINCH
  396.     (void)sigsetmask(oldmask);
  397. #endif
  398. }
  399.  
  400. /*
  401.  * Subroutine for vgetline to back up a single character position,
  402.  * backwards around end of lines (vgoto can't hack columns which are
  403.  * less than 0 in general).
  404.  */
  405. back1()
  406. {
  407.  
  408.     vgoto(destline - 1, WCOLS + destcol - 1);
  409. }
  410.  
  411. /*
  412.  * Get a line into genbuf after gcursor.
  413.  * Cnt limits the number of input characters
  414.  * accepted and is used for handling the replace
  415.  * single character command.  Aescaped is the location
  416.  * where we stick a termination indicator (whether we
  417.  * ended with an ESCAPE or a newline/return.
  418.  *
  419.  * We do erase-kill type processing here and also
  420.  * are careful about the way we do this so that it is
  421.  * repeatable.  (I.e. so that your kill doesn't happen,
  422.  * when you repeat an insert if it was escaped with \ the
  423.  * first time you did it.  commch is the command character
  424.  * involved, including the prompt for readline.
  425.  */
  426. char *
  427. vgetline(cnt, gcursor, aescaped, commch)
  428.     int cnt;
  429.     register char *gcursor;
  430.     bool *aescaped;
  431.     char commch;
  432. {
  433.     register int c, ch;
  434.     register char *cp;
  435.     int x, y, iwhite, backsl=0;
  436.     char *iglobp;
  437.     char cstr[2];
  438.     int (*OO)() = Outchar;
  439.  
  440.     /*
  441.      * Clear the output state and counters
  442.      * for autoindent backwards motion (counts of ^D, etc.)
  443.      * Remember how much white space at beginning of line so
  444.      * as not to allow backspace over autoindent.
  445.      */
  446.     *aescaped = 0;
  447.     ogcursor = gcursor;
  448.     flusho();
  449.     CDCNT = 0;
  450.     HADUP = 0;
  451.     HADZERO = 0;
  452.     gobbled = 0;
  453.     iwhite = whitecnt(genbuf);
  454.     iglobp = vglobp;
  455.  
  456.     /*
  457.      * Carefully avoid using vinschar in the echo area.
  458.      */
  459.     if (splitw)
  460.         Outchar = vputchar;
  461.     else {
  462.         Outchar = vinschar;
  463.         vprepins();
  464.     }
  465.     for (;;) {
  466.         backsl = 0;
  467.         if (gobblebl)
  468.             gobblebl--;
  469.         if (cnt != 0) {
  470.             cnt--;
  471.             if (cnt == 0)
  472.                 goto vadone;
  473.         }
  474.         c = getkey();
  475.         if (c != ATTN)
  476.             c &= (QUOTE|TRIM);
  477.         ch = c;
  478.         maphopcnt = 0;
  479.         if (vglobp == 0 && Peek_key == 0 && commch != 'r')
  480.             while ((ch = map(c, immacs)) != c) {
  481.                 c = ch;
  482.                 if (!value(REMAP))
  483.                     break;
  484.                 if (++maphopcnt > 256)
  485.                     error("Infinite macro loop");
  486.             }
  487.         if (!iglobp) {
  488.  
  489.             /*
  490.              * Erase-kill type processing.
  491.              * Only happens if we were not reading
  492.              * from untyped input when we started.
  493.              * Map users erase to ^H, kill to -1 for switch.
  494.              */
  495. #ifndef USG3TTY
  496.             if (c == tty.sg_erase)
  497.                 c = CTRL(h);
  498.             else if (c == tty.sg_kill)
  499.                 c = -1;
  500. #else
  501.             if (c == tty.c_cc[VERASE])
  502.                 c = CTRL(h);
  503.             else if (c == tty.c_cc[VKILL])
  504.                 c = -1;
  505. #endif
  506.             switch (c) {
  507.  
  508.             /*
  509.              * ^?        Interrupt drops you back to visual
  510.              *        command mode with an unread interrupt
  511.              *        still in the input buffer.
  512.              *
  513.              * ^\        Quit does the same as interrupt.
  514.              *        If you are a ex command rather than
  515.              *        a vi command this will drop you
  516.              *        back to command mode for sure.
  517.              */
  518.             case ATTN:
  519.             case QUIT:
  520.                 ungetkey(c);
  521.                 goto vadone;
  522.  
  523.             /*
  524.              * ^H        Backs up a character in the input.
  525.              *
  526.              * BUG:        Can't back around line boundaries.
  527.              *        This is hard because stuff has
  528.              *        already been saved for repeat.
  529.              */
  530.             case CTRL(h):
  531. bakchar:
  532.                 cp = gcursor - 1;
  533.                 if (cp < ogcursor) {
  534.                     if (splitw) {
  535.                         /*
  536.                          * Backspacing over readecho
  537.                          * prompt. Pretend delete but
  538.                          * don't beep.
  539.                          */
  540.                         ungetkey(c);
  541.                         goto vadone;
  542.                     }
  543.                     beep();
  544.                     continue;
  545.                 }
  546.                 goto vbackup;
  547.  
  548.             /*
  549.              * ^W        Back up a white/non-white word.
  550.              */
  551.             case CTRL(w):
  552.                 wdkind = 1;
  553.                 for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--)
  554.                     continue;
  555.                 for (c = wordch(cp - 1);
  556.                     cp > ogcursor && wordof(c, cp - 1); cp--)
  557.                     continue;
  558.                 goto vbackup;
  559.  
  560.             /*
  561.              * users kill    Kill input on this line, back to
  562.              *        the autoindent.
  563.              */
  564.             case -1:
  565.                 cp = ogcursor;
  566. vbackup:
  567.                 if (cp == gcursor) {
  568.                     beep();
  569.                     continue;
  570.                 }
  571.                 endim();
  572.                 *cp = 0;
  573.                 c = cindent();
  574.                 vgotoCL(qcolumn(cursor - 1, genbuf));
  575.                 if (doomed >= 0)
  576.                     doomed += c - cindent();
  577.                 gcursor = cp;
  578.                 continue;
  579.  
  580.             /*
  581.              * \        Followed by erase or kill
  582.              *        maps to just the erase or kill.
  583.              */
  584.             case '\\':
  585.                 x = destcol, y = destline;
  586.                 ex_putchar('\\');
  587.                 vcsync();
  588.                 c = getkey();
  589. #ifndef USG3TTY
  590.                 if (c == tty.sg_erase || c == tty.sg_kill)
  591. #else
  592.                 if (c == tty.c_cc[VERASE]
  593.                     || c == tty.c_cc[VKILL])
  594. #endif
  595.                 {
  596.                     vgoto(y, x);
  597.                     if (doomed >= 0)
  598.                         doomed++;
  599.                     goto def;
  600.                 }
  601.                 ungetkey(c), c = '\\';
  602.                 backsl = 1;
  603.                 break;
  604.  
  605.             /*
  606.              * ^Q        Super quote following character
  607.              *        Only ^@ is verboten (trapped at
  608.              *        a lower level) and \n forces a line
  609.              *        split so doesn't really go in.
  610.              *
  611.              * ^V        Synonym for ^Q
  612.              */
  613.             case CTRL(q):
  614.             case CTRL(v):
  615.                 x = destcol, y = destline;
  616.                 ex_putchar('^');
  617.                 vgoto(y, x);
  618.                 c = getkey();
  619. #ifdef TIOCSETC
  620.                 if (c == ATTN)
  621.                     c = nttyc.t_intrc;
  622. #endif
  623.                 if (c != NL) {
  624.                     if (doomed >= 0)
  625.                         doomed++;
  626.                     goto def;
  627.                 }
  628.                 break;
  629.             }
  630.         }
  631.  
  632.         /*
  633.          * If we get a blank not in the echo area
  634.          * consider splitting the window in the wrapmargin.
  635.          */
  636.         if (c != NL && !splitw) {
  637.             if (c == ' ' && gobblebl) {
  638.                 gobbled = 1;
  639.                 continue;
  640.             }
  641.             if (value(WRAPMARGIN) &&
  642.                 (outcol >= OCOLUMNS - value(WRAPMARGIN) ||
  643.                  backsl && outcol==0) &&
  644.                 commch != 'r') {
  645.                 /*
  646.                  * At end of word and hit wrapmargin.
  647.                  * Move the word to next line and keep going.
  648.                  */
  649.                 wdkind = 1;
  650.                 *gcursor++ = c;
  651.                 if (backsl)
  652.                     *gcursor++ = getkey();
  653.                 *gcursor = 0;
  654.                 /*
  655.                  * Find end of previous word if we are past it.
  656.                  */
  657.                 for (cp=gcursor; cp>ogcursor && isspace(cp[-1]); cp--)
  658.                     ;
  659.                 if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
  660.                     /*
  661.                      * Find beginning of previous word.
  662.                      */
  663.                     for (; cp>ogcursor && !isspace(cp[-1]); cp--)
  664.                         ;
  665.                     if (cp <= ogcursor) {
  666.                         /*
  667.                          * There is a single word that
  668.                          * is too long to fit.  Just
  669.                          * let it pass, but beep for
  670.                          * each new letter to warn
  671.                          * the luser.
  672.                          */
  673.                         c = *--gcursor;
  674.                         *gcursor = 0;
  675.                         beep();
  676.                         goto dontbreak;
  677.                     }
  678.                     /*
  679.                      * Save it for next line.
  680.                      */
  681.                     macpush(cp, 0);
  682.                     cp--;
  683.                 }
  684.                 macpush("\n", 0);
  685.                 /*
  686.                  * Erase white space before the word.
  687.                  */
  688.                 while (cp > ogcursor && isspace(cp[-1]))
  689.                     cp--;    /* skip blank */
  690.                 gobblebl = 3;
  691.                 goto vbackup;
  692.             }
  693.         dontbreak:;
  694.         }
  695.  
  696.         /*
  697.          * Word abbreviation mode.
  698.          */
  699.         cstr[0] = c;
  700.         if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) {
  701.             int wdtype, abno;
  702.  
  703.             cstr[1] = 0;
  704.             wdkind = 1;
  705.             cp = gcursor - 1;
  706.             for (wdtype = wordch(cp - 1);
  707.                 cp > ogcursor && wordof(wdtype, cp - 1); cp--)
  708.                 ;
  709.             *gcursor = 0;
  710.             for (abno=0; abbrevs[abno].mapto; abno++) {
  711.                 if (eq(cp, abbrevs[abno].cap)) {
  712.                     macpush(cstr, 0);
  713.                     macpush(abbrevs[abno].mapto, 1);
  714.                     goto vbackup;
  715.                 }
  716.             }
  717.         }
  718.  
  719.         switch (c) {
  720.  
  721.         /*
  722.          * ^M        Except in repeat maps to \n.
  723.          */
  724.         case CR:
  725.             if (vglobp)
  726.                 goto def;
  727.             c = '\n';
  728.             /* presto chango ... */
  729.  
  730.         /*
  731.          * \n        Start new line.
  732.          */
  733.         case NL:
  734.             *aescaped = c;
  735.             goto vadone;
  736.  
  737.         /*
  738.          * escape    End insert unless repeat and more to repeat.
  739.          */
  740.         case ESCAPE:
  741.             if (lastvgk)
  742.                 goto def;
  743.             goto vadone;
  744.  
  745.         /*
  746.          * ^D        Backtab.
  747.          * ^T        Software forward tab.
  748.          *
  749.          *        Unless in repeat where this means these
  750.          *        were superquoted in.
  751.          */
  752.         case CTRL(d):
  753.         case CTRL(t):
  754.             if (vglobp)
  755.                 goto def;
  756.             /* fall into ... */
  757.  
  758.         /*
  759.          * ^D|QUOTE    Is a backtab (in a repeated command).
  760.          */
  761.         case CTRL(d) | QUOTE:
  762.             *gcursor = 0;
  763.             cp = vpastwh(genbuf);
  764.             c = whitecnt(genbuf);
  765.             if (ch == CTRL(t)) {
  766.                 /*
  767.                  * ^t just generates new indent replacing
  768.                  * current white space rounded up to soft
  769.                  * tab stop increment.
  770.                  */
  771.                 if (cp != gcursor)
  772.                     /*
  773.                      * BUG:        Don't hack ^T except
  774.                      *        right after initial
  775.                      *        white space.
  776.                      */
  777.                     continue;
  778.                 cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
  779.                 ogcursor = cp;
  780.                 goto vbackup;
  781.             }
  782.             /*
  783.              * ^D works only if we are at the (end of) the
  784.              * generated autoindent.  We count the ^D for repeat
  785.              * purposes.
  786.              */
  787.             if (c == iwhite && c != 0)
  788.                 if (cp == gcursor) {
  789.                     iwhite = backtab(c);
  790.                     CDCNT++;
  791.                     ogcursor = cp = genindent(iwhite);
  792.                     goto vbackup;
  793.                 } else if (&cp[1] == gcursor &&
  794.                     (*cp == '^' || *cp == '0')) {
  795.                     /*
  796.                      * ^^D moves to margin, then back
  797.                      * to current indent on next line.
  798.                      *
  799.                      * 0^D moves to margin and then
  800.                      * stays there.
  801.                      */
  802.                     HADZERO = *cp == '0';
  803.                     ogcursor = cp = genbuf;
  804.                     HADUP = 1 - HADZERO;
  805.                     CDCNT = 1;
  806.                     endim();
  807.                     back1();
  808.                     vputchar(' ');
  809.                     goto vbackup;
  810.                 }
  811.             if (vglobp && vglobp - iglobp >= 2 &&
  812.                 (vglobp[-2] == '^' || vglobp[-2] == '0')
  813.                 && gcursor == ogcursor + 1)
  814.                 goto bakchar;
  815.             continue;
  816.  
  817.         default:
  818.             /*
  819.              * Possibly discard control inputs.
  820.              */
  821.             if (!vglobp && junk(c)) {
  822.                 beep();
  823.                 continue;
  824.             }
  825. def:
  826.             if (!backsl) {
  827.                 ex_putchar(c);
  828.                 flush();
  829.             }
  830.             if (gcursor > &genbuf[LBSIZE - 2])
  831.                 error("Line too long");
  832.             *gcursor++ = c & TRIM;
  833.             vcsync();
  834.             if (value(SHOWMATCH) && !iglobp)
  835.                 if (c == ')' || c == '}')
  836.                     lsmatch(gcursor);
  837.             continue;
  838.         }
  839.     }
  840. vadone:
  841.     *gcursor = 0;
  842.     if (Outchar != termchar)
  843.         Outchar = OO;
  844.     endim();
  845.     return (gcursor);
  846. }
  847.  
  848. int    vgetsplit();
  849. char    *vsplitpt;
  850.  
  851. /*
  852.  * Append the line in buffer at lp
  853.  * to the buffer after dot.
  854.  */
  855. vdoappend(lp)
  856.     char *lp;
  857. {
  858.     register int oing = inglobal;
  859.  
  860.     vsplitpt = lp;
  861.     inglobal = 1;
  862.     ignore(append(vgetsplit, dot));
  863.     inglobal = oing;
  864. }
  865.  
  866. /*
  867.  * Subroutine for vdoappend to pass to append.
  868.  */
  869. vgetsplit()
  870. {
  871.  
  872.     if (vsplitpt == 0)
  873.         return (EOF);
  874.     strcLIN(vsplitpt);
  875.     vsplitpt = 0;
  876.     return (0);
  877. }
  878.  
  879. /*
  880.  * Vmaxrep determines the maximum repetitition factor
  881.  * allowed that will yield total line length less than
  882.  * LBSIZE characters and also does hacks for the R command.
  883.  */
  884. vmaxrep(ch, cnt)
  885.     char ch;
  886.     register int cnt;
  887. {
  888.     register int len, replen;
  889.  
  890.     if (cnt > LBSIZE - 2)
  891.         cnt = LBSIZE - 2;
  892.     replen = strlen(genbuf);
  893.     if (ch == 'R') {
  894.         len = strlen(cursor);
  895.         if (replen < len)
  896.             len = replen;
  897.         CP(cursor, cursor + len);
  898.         vUD2 += len;
  899.     }
  900.     len = strlen(linebuf);
  901.     if (len + cnt * replen <= LBSIZE - 2)
  902.         return (cnt);
  903.     cnt = (LBSIZE - 2 - len) / replen;
  904.     if (cnt == 0) {
  905.         vsave();
  906.         error("Line too long");
  907.     }
  908.     return (cnt);
  909. }
  910.